package com.deductive.web.disposition.assumed;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.deductive.common.core.controller.BaseController;
import com.deductive.common.config.RuoYiConfig;
import com.deductive.common.core.domain.AjaxResult;
import com.deductive.common.core.page.TableDataInfo;
import com.deductive.common.utils.encrypt.MD5Util;
import com.deductive.domain.assumed.AssumedBasic;
import com.deductive.service.assumed.AssumedBasicService;
import com.deductive.service.sys.SysFilesService;
import com.deductive.domain.sys.SysFiles;
import com.deductive.service.assumed.EnemyInfoService;
import com.deductive.service.assumed.FriendlyInfoService;
import com.deductive.domain.assumed.AssumedEnemyInfo;
import com.deductive.domain.assumed.AssumedFriendlyInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.lang3.StringUtils;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.Arrays;
import java.util.Set;
import java.util.LinkedHashSet;
import java.util.stream.Collectors;

import javax.annotation.Resource;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.LocalDate;
import java.util.UUID;
import java.util.Date;
import java.util.List;

@RestController
@RequestMapping("/assumedBasic")
@Api(tags = "想定管理")
public class AssumedBasicController extends BaseController {

    @Resource
    private AssumedBasicService assumedBasicService;


    @Resource
    private SysFilesService sysFilesService;

    @Resource
    private EnemyInfoService enemyInfoService;

    @Resource
    private FriendlyInfoService friendlyInfoService;

    @GetMapping("/queryPage")
    @ApiOperation("想定分页列表查询")
    public TableDataInfo queryPage(@ApiParam(value = "查询条件：想定名称、背景、标识等") AssumedBasic xd) {
        startPage();
        LambdaQueryWrapper<AssumedBasic> eq = new LambdaQueryWrapper<>();
        eq.like(StringUtils.isNotBlank(xd.getScenarioName()), AssumedBasic::getScenarioName, xd.getScenarioName());
        eq.like(StringUtils.isNotBlank(xd.getScenarioBackground()), AssumedBasic::getScenarioBackground, xd.getScenarioBackground());
        eq.eq(xd.getScenarioId()!=null, AssumedBasic::getScenarioId, xd.getScenarioId());
        eq.orderByDesc(AssumedBasic::getCreateTime);
        List<AssumedBasic> list = assumedBasicService.list(eq);
        return getDataTable(list);
    }

    @GetMapping("/queryList")
    @ApiOperation("想定列表查询")
    public AjaxResult queryList(@ApiParam(value = "查询条件：想定名称、背景、标识等") AssumedBasic xd) {
        LambdaQueryWrapper<AssumedBasic> eq = new LambdaQueryWrapper<>();
        eq.like(StringUtils.isNotBlank(xd.getScenarioName()), AssumedBasic::getScenarioName, xd.getScenarioName());
        eq.like(StringUtils.isNotBlank(xd.getScenarioBackground()), AssumedBasic::getScenarioBackground, xd.getScenarioBackground());
        eq.eq(xd.getScenarioId()!=null, AssumedBasic::getScenarioId, xd.getScenarioId());
        eq.orderByDesc(AssumedBasic::getCreateTime);
        List<AssumedBasic> list = assumedBasicService.list(eq);
        return success(list);
    }

    @PostMapping("/update")
    @ApiOperation("想定修改")
    public boolean update(@ApiParam(value = "想定对象，包含需修改字段") @RequestBody AssumedBasic xd) {
        xd.setUpdateTime(new Date());
        return assumedBasicService.updateById(xd);
    }

    @PostMapping("/insert")
    @ApiOperation("想定新增")
    public boolean insert(@ApiParam(value = "想定对象") @RequestBody AssumedBasic xd) {
        xd.setCreateTime(new Date());
        return assumedBasicService.save(xd);
    }

    @DeleteMapping
    @ApiOperation("想定删除")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult delete(@ApiParam(value = "想定ID列表", required = true, example = "[1,2,3]") @RequestParam("idList") List<Long> idList) {
        // 删除关联文件（物理与数据库）后再删除想定
        List<AssumedBasic> basics = assumedBasicService.listByIds(idList);
        for (AssumedBasic basic : basics) {
            if (basic != null && StringUtils.isNotBlank(basic.getFileIds())) {
                List<Long> fileIds = Arrays.stream(basic.getFileIds().split(","))
                        .filter(StringUtils::isNotBlank)
                        .map(Long::valueOf)
                        .collect(Collectors.toList());
                if (!fileIds.isEmpty()) {
                    List<SysFiles> files = sysFilesService.listByIds(fileIds);
                    deletePhysicalFiles(files);
                    sysFilesService.removeByIds(fileIds);
                }
            }

            // 级联删除敌情及其文件
            if (basic != null && basic.getId() != null) {
                List<AssumedEnemyInfo> enemyInfos = enemyInfoService.list(new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<AssumedEnemyInfo>()
                        .eq(AssumedEnemyInfo::getAssumedId, basic.getId()));
                if (!enemyInfos.isEmpty()) {
                    // 收集文件ID
                    List<Long> enemyFileIds = enemyInfos.stream()
                            .filter(e -> StringUtils.isNotBlank(e.getFileIds()))
                            .flatMap(e -> Arrays.stream(e.getFileIds().split(",")))
                            .filter(StringUtils::isNotBlank)
                            .map(Long::valueOf)
                            .collect(Collectors.toList());
                    if (!enemyFileIds.isEmpty()) {
                        List<SysFiles> files = sysFilesService.listByIds(enemyFileIds);
                        deletePhysicalFiles(files);
                        sysFilesService.removeByIds(enemyFileIds);
                    }
                    // 删除敌情记录
                    enemyInfoService.removeByIds(enemyInfos.stream().map(AssumedEnemyInfo::getId).collect(Collectors.toList()));
                }
            }

            // 级联删除我情及其文件
            if (basic != null && basic.getId() != null) {
                List<AssumedFriendlyInfo> friendlyInfos = friendlyInfoService.list(new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<AssumedFriendlyInfo>()
                        .eq(AssumedFriendlyInfo::getAssumedId, basic.getId()));
                if (!friendlyInfos.isEmpty()) {
                    List<Long> friendlyFileIds = friendlyInfos.stream()
                            .filter(f -> StringUtils.isNotBlank(f.getFileIds()))
                            .flatMap(f -> Arrays.stream(f.getFileIds().split(",")))
                            .filter(StringUtils::isNotBlank)
                            .map(Long::valueOf)
                            .collect(Collectors.toList());
                    if (!friendlyFileIds.isEmpty()) {
                        List<SysFiles> files = sysFilesService.listByIds(friendlyFileIds);
                        deletePhysicalFiles(files);
                        sysFilesService.removeByIds(friendlyFileIds);
                    }
                    // 删除我情记录
                    friendlyInfoService.removeByIds(friendlyInfos.stream().map(AssumedFriendlyInfo::getId).collect(Collectors.toList()));
                }
            }
        }
        return AjaxResult.success(assumedBasicService.removeByIds(idList));
    }

    //--------------------------------------------------------------------------


    @GetMapping("/{id}/files")
    @ApiOperation("查询想定已绑定的文件列表")
    public AjaxResult listBoundFiles(@ApiParam(value = "想定ID", required = true, example = "1") @PathVariable("id") Long id) {
        AssumedBasic basic = assumedBasicService.getById(id);
        if (basic == null) {
            return error("想定不存在");
        }
        if (StringUtils.isBlank(basic.getFileIds())) {
            return success();
        }
        List<Long> ids = Arrays.stream(basic.getFileIds().split(","))
                .filter(StringUtils::isNotBlank)
                .map(Long::valueOf)
                .collect(Collectors.toList());
        return success(sysFilesService.listByIds(ids));
    }

    @PostMapping("/{id}/files/bind")
    @ApiOperation("为想定新增绑定文件（追加，不去重传入会自动去重,“通过查询文件管理的数据添加”）")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult bindFiles(@ApiParam(value = "想定ID", required = true, example = "1") @PathVariable("id") Long id,
                                @ApiParam(value = "文件ID列表", required = true, example = "[10,11]") @RequestBody List<Long> fileIdList) {
        AssumedBasic basic = assumedBasicService.getById(id);
        if (basic == null) {
            return error("想定不存在");
        }
        Set<Long> merged = new LinkedHashSet<>();
        if (StringUtils.isNotBlank(basic.getFileIds())) {
            merged.addAll(Arrays.stream(basic.getFileIds().split(","))
                    .filter(StringUtils::isNotBlank)
                    .map(Long::valueOf)
                    .collect(Collectors.toList()));
        }
        if (fileIdList != null) {
            merged.addAll(fileIdList);
        }
        basic.setFileIds(merged.stream().map(String::valueOf).collect(Collectors.joining(",")));
        basic.setUpdateTime(new Date());
        boolean ok = assumedBasicService.updateById(basic);
        return ok ? success("绑定成功") : error("绑定失败");
    }

    @PostMapping("/{id}/files/unbind")
    @ApiOperation("为想定移除绑定的文件")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult unbindFiles(@ApiParam(value = "想定ID", required = true, example = "1") @PathVariable("id") Long id,
                                  @ApiParam(value = "文件ID列表", required = true, example = "[10,11]") @RequestBody List<Long> fileIdList) {
        AssumedBasic basic = assumedBasicService.getById(id);
        if (basic == null) {
            return error("想定不存在");
        }
        if (StringUtils.isBlank(basic.getFileIds())) {
            return success("无绑定文件");
        }
        Set<Long> existing = Arrays.stream(basic.getFileIds().split(","))
                .filter(StringUtils::isNotBlank)
                .map(Long::valueOf)
                .collect(Collectors.toCollection(LinkedHashSet::new));
        if (fileIdList != null) {
            existing.removeAll(new LinkedHashSet<>(fileIdList));
        }
        basic.setFileIds(existing.stream().map(String::valueOf).collect(Collectors.joining(",")));
        basic.setUpdateTime(new Date());
        boolean ok = assumedBasicService.updateById(basic);
        return ok ? success("移除成功") : error("移除失败");
    }

    @PostMapping("/{id}/files/upload")
    @ApiOperation("上传文件并绑定到想定")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult uploadAndBind(@ApiParam(value = "想定ID", required = true, example = "1") @PathVariable("id") Long id,
                                    @ApiParam(value = "上传文件", required = true) @RequestPart("file") MultipartFile file,
                                    @ApiParam(value = "父目录ID，可选") @RequestParam(value = "parentId", required = false) Long parentId) {
        AssumedBasic basic = assumedBasicService.getById(id);
        if (basic == null) {
            return error("想定不存在");
        }
        if (file == null || file.isEmpty()) {
            return error("上传文件不能为空");
        }
        try {
            String originalFilename = file.getOriginalFilename();
            if (originalFilename == null || originalFilename.trim().isEmpty()) {
                return error("文件名不能为空");
            }
            String extension = "";
            int lastDotIndex = originalFilename.lastIndexOf(".");
            if (lastDotIndex > 0) {
                extension = originalFilename.substring(lastDotIndex + 1).toLowerCase();
            }

            String storageName = UUID.randomUUID().toString().replace("-", "");
            if (!extension.isEmpty()) {
                storageName += "." + extension;
            }

            String baseDir = RuoYiConfig.getFilePath();
            String datePath = LocalDate.now().toString();
            String uploadDir = baseDir + "/" + datePath;
            Path dir = Paths.get(uploadDir);
            if (!Files.exists(dir)) {
                Files.createDirectories(dir);
            }

            String fullPath = uploadDir + "/" + storageName;
            Path targetPath = Paths.get(fullPath);
            Files.copy(file.getInputStream(), targetPath);

            String md5Hash = MD5Util.calculateMD5(file.getBytes());

            SysFiles sysFiles = new SysFiles();
            sysFiles.setFileName(originalFilename);
            sysFiles.setStorageName(storageName);
            sysFiles.setFilePath("/profile/files/" + datePath + "/" + storageName);
            sysFiles.setFileSize(file.getSize());
            sysFiles.setMimeType(file.getContentType());
            sysFiles.setExtension(extension);
            sysFiles.setMd5Hash(md5Hash);
            sysFiles.setUploadTime(new Date());
            sysFiles.setLastModified(new Date());
            sysFiles.setVersion(1);
            sysFiles.setParentId(parentId);
            sysFiles.setIsDirectory(false);
            sysFiles.setStatus(1);

            boolean saved = sysFilesService.save(sysFiles);
            if (!saved) {
                Files.deleteIfExists(targetPath);
                return error("文件保存失败");
            }

            // 绑定ID
            List<Long> newIds = new java.util.ArrayList<>();
            newIds.add(sysFiles.getId());
            Set<Long> merged = new LinkedHashSet<>();
            if (StringUtils.isNotBlank(basic.getFileIds())) {
                merged.addAll(Arrays.stream(basic.getFileIds().split(","))
                        .filter(StringUtils::isNotBlank)
                        .map(Long::valueOf)
                        .collect(Collectors.toList()));
            }
            merged.addAll(newIds);
            basic.setFileIds(merged.stream().map(String::valueOf).collect(Collectors.joining(",")));
            basic.setUpdateTime(new Date());
            boolean ok = assumedBasicService.updateById(basic);
            if (!ok) {
                // 回滚文件
                sysFilesService.removeById(sysFiles.getId());
                Files.deleteIfExists(targetPath);
                return error("绑定失败");
            }
            return success(sysFiles).put("msg", "上传并绑定成功");
        } catch (IOException e) {
            return error("文件上传失败：" + e.getMessage());
        } catch (Exception e) {
            return error("系统错误：" + e.getMessage());
        }
    }

    private void deletePhysicalFiles(List<SysFiles> files) {
        for (SysFiles file : files) {
            try {
                String physicalPath = file.getFilePath().replace("/profile/", RuoYiConfig.getProfile() + "/");
                Path filePath = Paths.get(physicalPath);
                if (Files.exists(filePath)) {
                    Files.delete(filePath);
                    deleteEmptyDirectories(filePath.getParent());
                }
            } catch (IOException e) {
                logger.warn("删除物理文件失败: {}", file.getFilePath());
            }
        }
    }

    private void deleteEmptyDirectories(Path directory) {
        try {
            if (directory != null && Files.exists(directory)) {
                if (Files.list(directory).count() == 0) {
                    Files.delete(directory);
                    deleteEmptyDirectories(directory.getParent());
                }
            }
        } catch (IOException ignored) { }
    }



}
